package u.can.i.up;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.ssca.dex.DexParser;
import com.ssca.format.DexMethod;

import u.can.i.up.db.PgSession;
import u.can.i.up.db.postgre.AppInfo;
import u.can.i.up.db.postgre.AppInfoDAO;
import u.can.i.up.db.postgre.AppReferedMethodInfo;
import u.can.i.up.db.postgre.AppReferedMethodInfoDAO;
import u.can.i.up.db.postgre.ReferedMethodInfo;
import u.can.i.up.db.postgre.ReferedMethodInfoDAO;
import u.can.i.up.utils.ApkUtil;
import u.can.i.up.utils.FileUtil;

public class MainMalicious {

	private static Logger logger = LogManager.getLogger();

	public static void main(String[] args) {
		// 0.初始化.
		SqlSession sqlSession = PgSession.getInstance().getSqlSession();
		int affectedLines = 0;
		int insertBufferSize = 500;
		String folderPath = "E:\\工作目录\\2015样本";

		// 1.遍历所有文件.
		logger.info("STEP[1] Traversal: {" + folderPath + "}");
		List<String> paths = FileUtil.getAllPathList(folderPath);
		logger.info("STEP[1] File number: [" + paths.size() + "]");
		for (int i = 0; i < paths.size(); i++) {
			logger.info("======================{" + i + "}=======================");
			String locate_path = paths.get(i);
			if (!locate_path.endsWith(".apk")) {
				continue;
			}
			// 2.计算md5.
			String md5 = FileUtil.getMD5byPath(locate_path);
			logger.info("STEP[2] File MD5: {" + md5 + "}");

			// 3.计算refered_method.
			logger.info("STEP[3] Parsing APK: {" + locate_path + "}");
			List<DexMethod> referedMethod = null;
			try {
				referedMethod = DexParser.getReferedListFromApk(locate_path);
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (referedMethod == null) {
				continue;
			}

			// 3.插入app_info.
			AppInfoDAO appInfoDAO = sqlSession.getMapper(AppInfoDAO.class);
			AppInfo appInfo = new AppInfo();
			String packagename = ApkUtil.getPackageNameByApkPath(locate_path);
			appInfo.setPackage_name((packagename != null) ? (packagename) : (""));
			appInfo.setVersion("0");
			appInfo.setVersion_code(0);
			appInfo.setPath(locate_path);
			appInfo.setMd5(md5);
			int affectedLine = -1;
			int id = -1;
			try {
				affectedLine = appInfoDAO.insertAppInfo(appInfo);
				sqlSession.commit();
				appInfo = appInfoDAO.getAppInfo(md5);
				id = appInfo.getId();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			logger.info(
					"STEP[4] Insert File MD5: {" + md5 + "}, affectedLine: [" + affectedLine + "], id: {" + id + "}");

			// 5. 存入refered_method_info表中.
			logger.info("STEP[5] Inserting Refered Method Into {refered_method_info}...");
			List<ReferedMethodInfo> referedMethodInfoList = new ArrayList<ReferedMethodInfo>();
			try {
				ReferedMethodInfoDAO referedMethodInfoDAO = sqlSession.getMapper(ReferedMethodInfoDAO.class);
				affectedLines = 0;
				if (referedMethod != null && !referedMethod.isEmpty()) {
					for (DexMethod dm : referedMethod) {
						referedMethodInfoList.add(new ReferedMethodInfo(dm));
						if (referedMethodInfoList != null && referedMethodInfoList.size() >= insertBufferSize) {
							affectedLines += referedMethodInfoDAO.insertReferedMethodInfoList(referedMethodInfoList);
							sqlSession.commit();
							referedMethodInfoList.clear();
						}
					}
					if (referedMethodInfoList != null && !referedMethodInfoList.isEmpty()) {
						affectedLines += referedMethodInfoDAO.insertReferedMethodInfoList(referedMethodInfoList);
						sqlSession.commit();
					}
				}
				logger.info("STEP[5] Done. Affected Lines: " + affectedLines);
			} catch (Exception e) {
				sqlSession.commit();
				e.printStackTrace();
			}

			// 6. 并且建立关联.
			logger.info("STEP[6] Inserting App-ReferedMethod Into {app_refered_method_info}...");
			List<AppReferedMethodInfo> appReferedMethodInfoList = new ArrayList<AppReferedMethodInfo>();
			try {
				AppReferedMethodInfoDAO appReferedMethodInfoDAO = sqlSession.getMapper(AppReferedMethodInfoDAO.class);
				affectedLines = 0;
				if (referedMethod != null && !referedMethod.isEmpty()) {
					for (DexMethod dm : referedMethod) {
						appReferedMethodInfoList.add(new AppReferedMethodInfo(appInfo.getId(), dm));
						if (appReferedMethodInfoList != null && appReferedMethodInfoList.size() >= insertBufferSize) {
							affectedLines += appReferedMethodInfoDAO
									.insertAppReferedMethodInfoList(appReferedMethodInfoList);
							sqlSession.commit();
							appReferedMethodInfoList.clear();
						}
					}
					if (appReferedMethodInfoList != null && !appReferedMethodInfoList.isEmpty()) {
						affectedLines += appReferedMethodInfoDAO
								.insertAppReferedMethodInfoList(appReferedMethodInfoList);
						sqlSession.commit();
					}
				}
				logger.info("STEP[6] Done. Affected Lines: " + affectedLines);
			} catch (Exception e) {
				sqlSession.commit();
				e.printStackTrace();
			}
		}
	}

}
